broadway: Add linear gradient node
authorAlexander Larsson <alexl@redhat.com>
Wed, 22 Nov 2017 11:31:36 +0000 (12:31 +0100)
committerAlexander Larsson <alexl@redhat.com>
Thu, 23 Nov 2017 09:48:29 +0000 (10:48 +0100)
gdk/broadway/broadway-protocol.h
gdk/broadway/broadway.js
gdk/broadway/broadwayd.c
gsk/gskbroadwayrenderer.c

index bc772d98ea8b8155fce9eed7bbd48c82cc110b0d..e4ce21e6e174c902be8e93ae719f12a91c72ef8a 100644 (file)
@@ -16,6 +16,7 @@ typedef enum { /* Sync changes with broadway.js */
   BROADWAY_NODE_OUTSET_SHADOW = 4,
   BROADWAY_NODE_INSET_SHADOW = 5,
   BROADWAY_NODE_ROUNDED_CLIP = 6,
+  BROADWAY_NODE_LINEAR_GRADIENT = 7,
 } BroadwayNodeType;
 
 typedef enum {
index 68f7b8afbc87a9ce9b1012b8a91124960a098ecd..45dae027f100dad69c77e07d1b4b380dd2af2c04 100644 (file)
@@ -331,15 +331,16 @@ SwapNodes.prototype.decode_int32 = function() {
 
 SwapNodes.prototype.decode_color = function() {
     var rgba = this.decode_uint32();
-    a = (rgba >> 24) & 0xff;
-    r = (rgba >> 16) & 0xff;
-    g = (rgba >> 8) & 0xff;
-    b = (rgba >> 0) & 0xff;
+    var a = (rgba >> 24) & 0xff;
+    var r = (rgba >> 16) & 0xff;
+    var g = (rgba >> 8) & 0xff;
+    var b = (rgba >> 0) & 0xff;
+    var c;
     if (a == 0)
         c = "rgb(" + r + "," + g + "," + b + ")";
     else
         c = "rgba(" + r + "," + g + "," + b + "," + (a / 255.0) + ")";
-    return c
+    return c;
 }
 
 SwapNodes.prototype.decode_float = function() {
@@ -350,7 +351,14 @@ SwapNodes.prototype.decode_size = function() {
     var s = new Object();
     s.width = this.decode_float ();
     s.height = this.decode_float ();
-    return s
+    return s;
+}
+
+SwapNodes.prototype.decode_point = function() {
+    var p = new Object();
+    p.x = this.decode_float ();
+    p.y = this.decode_float ();
+    return p;
 }
 
 SwapNodes.prototype.decode_rect = function() {
@@ -374,10 +382,25 @@ SwapNodes.prototype.decode_irect = function() {
 SwapNodes.prototype.decode_rounded_rect = function() {
     var r = new Object();
     r.bounds = this.decode_rect();
-    r.sizes = []
+    r.sizes = [];
     for (var i = 0; i < 4; i++)
         r.sizes[i] = this.decode_size();
-    return r
+    return r;
+}
+
+SwapNodes.prototype.decode_color_stop = function() {
+    var s = new Object();
+    s.offset = this.decode_float ();
+    s.color = this.decode_color ();
+    return s;
+}
+
+SwapNodes.prototype.decode_color_stops = function() {
+    var stops = [];
+    var len = this.decode_uint32();
+    for (var i = 0; i < len; i++)
+        stops[i] = this.decode_color_stop();
+    return stops;
 }
 
 function args() {
@@ -524,6 +547,51 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y)
         }
         break;
 
+    case 7:  // LINEAR_GRADIENT
+        {
+            var rect = this.decode_rect();
+            var start = this.decode_point ();
+            var end = this.decode_point ();
+            var stops = this.decode_color_stops ();
+            var div = document.createElement('div');
+            div.style["position"] = "absolute";
+            set_rect_style(div, rect, offset_x, offset_y);
+
+            // direction:
+            var dx = end.x - start.x;
+            var dy = end.y - start.y;
+
+            // Angle in css coords (clockwise degrees, up = 0), note that y goes downwards so we have to invert
+            var angle = Math.atan2(dx, -dy) * 180.0 / Math.PI;
+
+            // Figure out which corner has offset == 0 in css
+            var start_corner_x, start_corner_y;
+            if (dx >= 0) // going right
+                start_corner_x = rect.x;
+            else
+                start_corner_x = rect.x + rect.width;
+            if (dy >= 0) // going down
+                start_corner_y = rect.y;
+            else
+                start_corner_y = rect.y + rect.height;
+
+            /* project start corner on the line */
+            var l2 = dx*dx + dy*dy;
+            var l = Math.sqrt(l2);
+            var offset = ((start_corner_x - start.x) * dx  + (start_corner_y - start.y) * dy) / l2;
+
+            var gradient = "linear-gradient(" + angle + "deg";
+            for (var i = 0; i < stops.length; i++) {
+                var stop = stops[i];
+                gradient = gradient + ", " + stop.color + " " + px(stop.offset * l - offset);
+            }
+            gradient = gradient + ")";
+
+            div.style["background-image"] = gradient;
+            parent.appendChild(div);
+        }
+        break;
+
     default:
         alert("Unexpected node type " + type);
     }
index b3ebd4b02d0333a657abafb9f167ab37e2aaafea..693e76cab5299aac9b0e1fda0992c3e915a57347 100644 (file)
@@ -221,13 +221,14 @@ get_client_serial (BroadwayClient *client, guint32 daemon_serial)
 #define NODE_SIZE_SIZE 2
 #define NODE_SIZE_RECT (NODE_SIZE_POINT + NODE_SIZE_SIZE)
 #define NODE_SIZE_RRECT (NODE_SIZE_RECT + 4 * NODE_SIZE_SIZE)
+#define NODE_SIZE_COLOR_STOP (NODE_SIZE_FLOAT + NODE_SIZE_COLOR)
 
 static int
 rewrite_node_textures (BroadwayClient *client,
                        int len, guint32 data[], int pos)
 {
   guint32 type;
-  guint32 i, n_children;
+  guint32 i, n_children, n_stops;
 
   g_assert (pos < len);
 
@@ -257,6 +258,11 @@ rewrite_node_textures (BroadwayClient *client,
     pos += NODE_SIZE_RRECT;
     pos = rewrite_node_textures (client, len, data, pos);
     break;
+  case BROADWAY_NODE_LINEAR_GRADIENT:
+    pos += NODE_SIZE_RECT + 2 * NODE_SIZE_POINT;
+    n_stops = data[pos++];
+    pos += n_stops * NODE_SIZE_COLOR_STOP;
+    break;
   default:
     g_assert_not_reached ();
   }
index 0720369078fa506646ff192ad40309941716ea97..b2ead65792e7b18ae535feddd669d3842a9c5b79 100644 (file)
@@ -145,6 +145,13 @@ add_rounded_rect (GArray *nodes, const GskRoundedRect *rrect)
     add_size (nodes, &rrect->corner[i]);
 }
 
+static void
+add_color_stop (GArray *nodes, const GskColorStop *stop)
+{
+  add_float (nodes, stop->offset);
+  add_rgba (nodes, &stop->color);
+}
+
 static void
 gsk_broadway_renderer_add_node (GskRenderer *self,
                                 GArray *nodes,
@@ -228,6 +235,21 @@ gsk_broadway_renderer_add_node (GskRenderer *self,
       }
       return;
 
+    case GSK_LINEAR_GRADIENT_NODE:
+      {
+        guint i, n;
+
+        add_uint32 (nodes, BROADWAY_NODE_LINEAR_GRADIENT);
+        add_rect (nodes, &node->bounds);
+        add_point (nodes, gsk_linear_gradient_node_peek_start (node));
+        add_point (nodes, gsk_linear_gradient_node_peek_end (node));
+        n = gsk_linear_gradient_node_get_n_color_stops (node);
+        add_uint32 (nodes, n);
+        for (i = 0; i < n; i++)
+          add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]);
+      }
+      return;
+
     default:
       {
         cairo_surface_t *surface;